﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GpuStructCompiler
{
    public enum TokenType
    {
        Identifier, LBrace, RBrace, Comma, Colon, Semicolon
    }
    public class Token
    {
        public TokenType TokenType;
        public string Text { get; set; }
    }
    public class Lexer
    {
        enum LexerState
        {
            Start, Identifier, Punctuator, Comment
        }
        public static IEnumerable<Token> Parse(string text)
        {
            int ptr = 0;
            LexerState state = LexerState.Start;
            StringBuilder curToken = new StringBuilder();
            while (ptr < text.Length)
            {
                char curChar = text[ptr];
                char nextChar = ' ';
                if (ptr + 1 < text.Length)
                    nextChar = text[ptr + 1];
                switch (state)
                {
                    case LexerState.Start:
                        {
                            if (Char.IsLetter(curChar) || curChar == '_')
                                state = LexerState.Identifier;
                            else if (curChar == '/' && nextChar == '/')
                                state = LexerState.Comment;
                            else if (char.IsPunctuation(curChar))
                                state = LexerState.Punctuator;
                            else
                                ptr++;
                            curToken.Clear();
                        }
                        break;
                    case LexerState.Comment:
                        {
                            if (curChar == '\n')
                                state = LexerState.Start;
                            ptr++;
                        }
                        break;
                    case LexerState.Identifier:
                        {
                            if (char.IsLetterOrDigit(curChar) || curChar == '_')
                            {
                                curToken.Append(curChar);
                                ptr++;
                            }
                            else
                            {
                                yield return new Token() { TokenType = TokenType.Identifier, Text = curToken.ToString() };
                                state = LexerState.Start;
                            }
                        }
                        break;
                    case LexerState.Punctuator:
                        {
                            if (curChar == ',')
                            {
                                yield return new Token() { TokenType = TokenType.Comma };
                            }
                            else if (curChar == ';')
                            {
                                yield return new Token() { TokenType = TokenType.Semicolon };
                            }
                            else if (curChar == '{')
                            {
                                yield return new Token() { TokenType = TokenType.LBrace };
                            }
                            else if (curChar == '}')
                            {
                                yield return new Token() { TokenType = TokenType.RBrace };
                            }
                            else
                            {
                                state = LexerState.Start;
                                continue;
                            }
                            ptr++;
                        }
                        break;
                    default:
                        throw new Exception("Illegal character");
                }
            }
        }
    }
}
